using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PACKETPARSERMAX20.CORE;

namespace PACKETPARSERMAX20.CORE.DEFINITIONS
{
    public class SMSG_SPELL_GO_DEF : DefinitionBase
    {
        public override bool Process()
        {
            ResetPosition();

            //base.Stream.Position = base.Stream.Length;

            //return Validate();

           // InitLog();


            SpellCastFlags castFlags = 0;
            byte m_cast_count = 0;
            UInt32 m_spellInfoId = 0;

            UInt64 m_castitem_or_caster = popGuid();
            UInt64 m_caster = popGuid();

            //if (LogIt) LogAppendLine("UInt64", "m_castitem_or_caster", m_castitem_or_caster, true);
            //if (LogIt) LogAppendLine("UInt64", "m_caster", m_caster, true);

            if (ClientBuild >= 9183)
            {
                m_cast_count = ReadByte();                             // pending spell cast?
                m_spellInfoId = ReadUInt32();                        // spellId
                castFlags = (SpellCastFlags)ReadUInt32();

                //if (LogIt) LogAppendLine("byte", "m_cast_count", m_cast_count);
                //if (LogIt) LogAppendLine("UInt32", "m_spellInfoId", m_spellInfoId);
                //if (LogIt) LogAppendLine("UInt32", "castFlags", m_cast_count, "", castFlags.DumpFlags());
            }
            else
            {
                m_spellInfoId = ReadUInt32();
                m_cast_count = ReadByte();                           // single cast or multi 2.3 (0/1)
                castFlags = (SpellCastFlags)ReadUInt16();

                //if (LogIt) LogAppendLine("UInt32", "m_spellInfoId", m_spellInfoId);
                //if (LogIt) LogAppendLine("byte", "m_cast_count", m_cast_count);
                //if (LogIt) LogAppendLine("UInt16", "castFlags", m_cast_count, "", castFlags.DumpFlags());

            }


            UInt32 getMSTime = ReadUInt32();                          // timestamp
            //if (LogIt) LogAppendLine("UInt32", "getMSTime", getMSTime);

            byte m_countOfHit = ReadByte();
            for (int i = 0; i < m_countOfHit; i++)
            {
                UInt64 targetGUID = ReadUInt64();
                //if (LogIt) LogAppendLine("UInt32", "targetGUID", targetGUID, i, true);
            }

            byte m_countOfMiss = ReadByte();
            if (!((castFlags & SpellCastFlags.CAST_FLAG_UNKNOWN3) > 0) || ClientBuild >= 9947)
            {
                for (int i = 0; i < m_countOfMiss; i++)
                {
                    // Add only miss

                    UInt64 targetGUID = ReadUInt64();
                    SpellMissInfo missCondition = (SpellMissInfo)ReadByte();

                    //if (LogIt) LogAppendLine("UInt32", "targetGUID", targetGUID, i, "CAST_FLAG_UNKNOWN3", true);
                    //if (LogIt) LogAppendLine("byte", "missCondition", (byte)missCondition, i, "CAST_FLAG_UNKNOWN3", missCondition.DumpFlags());


                    if (missCondition == SpellMissInfo.SPELL_MISS_REFLECT)
                    {
                        byte reflectResult = ReadByte();
                        //if (LogIt) LogAppendLine("byte", "reflectResult", reflectResult, i, "SPELL_MISS_REFLECT");

                    }

                }
            }

            SpellCastTargetFlags m_targetMask = (SpellCastTargetFlags)ReadUInt32();
            //if (LogIt) LogAppendLine("UInt32", "m_targetMask", (uint)m_targetMask, "", m_targetMask.DumpFlags());

            if ((m_targetMask & (SpellCastTargetFlags.TARGET_FLAG_UNIT | SpellCastTargetFlags.TARGET_FLAG_PVP_CORPSE | SpellCastTargetFlags.TARGET_FLAG_OBJECT | SpellCastTargetFlags.TARGET_FLAG_OBJECT_UNK | SpellCastTargetFlags.TARGET_FLAG_CORPSE | SpellCastTargetFlags.TARGET_FLAG_UNK2)) > 0)
            {
                if ((m_targetMask & SpellCastTargetFlags.TARGET_FLAG_UNIT) > 0)
                {
                    ulong m_unitTarget = popGuid();
                    //if (LogIt) LogAppendLine("UInt64", "m_unitTarget", m_unitTarget, "TARGET_FLAG_UNIT", true);
                }
                else if ((m_targetMask & (SpellCastTargetFlags.TARGET_FLAG_OBJECT | SpellCastTargetFlags.TARGET_FLAG_OBJECT_UNK)) > 0)
                {
                    ulong m_GOTarget = popGuid();
                    //if (LogIt) LogAppendLine("UInt64", "m_GOTarget", m_GOTarget, "TARGET_FLAG_OBJECT | TARGET_FLAG_OBJECT_UNK", true);
                }
                else if ((m_targetMask & (SpellCastTargetFlags.TARGET_FLAG_CORPSE | SpellCastTargetFlags.TARGET_FLAG_PVP_CORPSE)) > 0)
                {
                    ulong m_CorpseTargetGUID = popGuid();
                    //if (LogIt) LogAppendLine("UInt64", "m_CorpseTargetGUID", m_CorpseTargetGUID, "TARGET_FLAG_CORPSE | TARGET_FLAG_PVP_CORPSE", true);
                }
                else
                {
                    ulong m_other_guid = popGuid();
                    //if (LogIt) LogAppendLine("UInt64", "m_other_guid", m_other_guid, true);
                }
            }

            if ((m_targetMask & (SpellCastTargetFlags.TARGET_FLAG_ITEM | SpellCastTargetFlags.TARGET_FLAG_TRADE_ITEM)) > 0)
            {
                ulong m_itemTarget = popGuid();
                //if (LogIt) LogAppendLine("UInt64", "m_itemTarget", m_itemTarget, "TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM", true);
            }

            if ((m_targetMask & SpellCastTargetFlags.TARGET_FLAG_SOURCE_LOCATION) > 0)
            {
                if (ClientBuild >= 10314)
                {
                    byte unkb = ReadByte();
                    //if (LogIt) LogAppendLine("byte", "unkb", unkb, "TARGET_FLAG_SOURCE_LOCATION");
                }
 
                float m_srcX = ReadSingle();
                float m_srcY = ReadSingle();
                float m_srcZ = ReadSingle();

                //if (LogIt) LogAppendLine("float", "m_srcX", m_srcX, "TARGET_FLAG_SOURCE_LOCATION");
                //if (LogIt) LogAppendLine("float", "m_srcY", m_srcY, "TARGET_FLAG_SOURCE_LOCATION");
                //if (LogIt) LogAppendLine("float", "m_srcZ", m_srcZ, "TARGET_FLAG_SOURCE_LOCATION");
            }

            if ((m_targetMask & SpellCastTargetFlags.TARGET_FLAG_DEST_LOCATION) > 0)
            {
                if (ClientBuild >= 9551)
                {
                    byte unkb = ReadByte();
                    //if (LogIt) LogAppendLine("byte", "unkb", unkb, "TARGET_FLAG_DEST_LOCATION");
                }

                float m_destX = ReadSingle();
                float m_destY = ReadSingle();
                float m_destZ = ReadSingle();

                //if (LogIt) LogAppendLine("float", "m_destX", m_destX, "TARGET_FLAG_DEST_LOCATION");
                //if (LogIt) LogAppendLine("float", "m_destY", m_destY, "TARGET_FLAG_DEST_LOCATION");
                //if (LogIt) LogAppendLine("float", "m_destZ", m_destZ, "TARGET_FLAG_DEST_LOCATION");
            }

            if ((m_targetMask & SpellCastTargetFlags.TARGET_FLAG_STRING) > 0)
            {
                string m_strTarget = ReadString();

                //if (LogIt) LogAppendLine("string", "m_strTarget", m_strTarget, "TARGET_FLAG_STRING");
            }

            if (ClientBuild >= 9183)
            {

                if ((castFlags & SpellCastFlags.CAST_FLAG_UNKNOWN6) > 0)                  // predicted power?
                {
                    UInt32 predicted_power = ReadUInt32();
                    //if (LogIt) LogAppendLine("UInt32", "predicted_power", predicted_power, "CAST_FLAG_UNKNOWN6");
                }
                if ((castFlags & SpellCastFlags.CAST_FLAG_UNKNOWN7) > 0)                   // rune cooldowns list
                {
                    byte runes_state_before = ReadByte();                                  // runes state before
                    byte runes_state_after = ReadByte();                                 // runes state after

                    //if (LogIt) LogAppendLine("byte", "runes_state_before", runes_state_before, "CAST_FLAG_UNKNOWN7");
                    //if (LogIt) LogAppendLine("byte", "runes_state_after", runes_state_after, "CAST_FLAG_UNKNOWN7");

                    for (byte i = 0; i < 6; ++i)
                    {
                        byte m = (byte)(1 << (int)i);
                        if ((m & runes_state_before) > 0)
                        {
                            // usable before...
                            if (!((m & runes_state_after) > 0))                               // ...but on cooldown now...
                            {
                                byte unk = ReadByte();                       // some unknown byte (time?)

                                //if (LogIt) LogAppendLine("byte", "unk", unk, i);
                            }
                        }
                    }
                }

                if ((castFlags & SpellCastFlags.CAST_FLAG_UNKNOWN4) > 0)                    // unknown wotlk
                {
                    float unk_float = ReadSingle();
                    UInt32 unk_UInt32 = ReadUInt32();
                    //if (LogIt) LogAppendLine("float", "unk_float", unk_float, "CAST_FLAG_UNKNOWN4");
                    //if (LogIt) LogAppendLine("UInt32", "unk_UInt32", unk_UInt32, "CAST_FLAG_UNKNOWN4");
                }


                //if ((castFlags & (SpellCastFlags.CAST_FLAG_UNKNOWN12 | SpellCastFlags.CAST_FLAG_UNKNOWN17 | SpellCastFlags.CAST_FLAG_UNKNOWN13)) > 0)                    // unknown wotlk
                //{
                //    byte unkb = ReadByte();
                //  //  if(LogIt) LogAppendLine("byte", "unkb", unkb, "CAST_FLAG_UNKNOWN12 | CAST_FLAG_UNKNOWN17 | CAST_FLAG_UNKNOWN13");

                //}

            }

            if ((castFlags & SpellCastFlags.CAST_FLAG_AMMO) > 0)
            {
                UInt32 ammoDisplayID = ReadUInt32();
                UInt32 ammoInventoryType = ReadUInt32();

                //if (LogIt) LogAppendLine("UInt32", "ammoDisplayID", ammoDisplayID, "CAST_FLAG_AMMO");
                //if (LogIt) LogAppendLine("UInt32", "ammoInventoryType", ammoInventoryType, "CAST_FLAG_AMMO");

            }


            if ((castFlags & SpellCastFlags.CAST_FLAG_UNKNOWN5) > 0)                   // unknown wotlk
            {
                UInt32 unk1 = ReadUInt32();
                UInt32 unk2 = ReadUInt32();

                //if (LogIt) LogAppendLine("UInt32", "unk1", unk1, "CAST_FLAG_UNKNOWN5");
                //if (LogIt) LogAppendLine("UInt32", "unk2", unk2, "CAST_FLAG_UNKNOWN5");
            }

            if ((m_targetMask & SpellCastTargetFlags.TARGET_FLAG_DEST_LOCATION) > 0)
            {
                if (ClientBuild >= 9551)
                {
                    byte unkb2 = ReadByte();
                    //if (LogIt) LogAppendLine("byte", "unkb2", unkb2, "TARGET_FLAG_DEST_LOCATION");
                }

            }
            return Validate();
        }


        //public override bool Process()
        //{
        //    ResetPosition();


        //    //if(m_CastItem)
        //    //    data.append(m_CastItem->GetPackGUID());
        //    //else
        //    //    data.append(m_caster->GetPackGUID());

        //    UInt64 m_castitem_or_caster = popGuid();
        //    UInt64 m_caster = popGuid();

        //    UInt64 m_spellInfoId = ReadUInt32();
        //    UInt16 castFlags = ReadUInt16();
        //    UInt32 getMSTime = ReadUInt32();                          // timestamp

        //    byte m_countOfHit = ReadByte();


        //    for (int i = 0; i < m_countOfHit; i++)
        //    {
        //        //m_UniqueTargetInfo
        //        UInt64 targetGUID = ReadUInt64();
        //    }

        //    //for (int i = 0; i < m_countOfHit; i++)
        //    //{
        //    //    //m_UniqueGOTargetInfo
        //    //    UInt64 targetGUID = ReadUInt64();// Always hits
        //    //}

        //    byte m_countOfMiss = ReadByte();

        //    for (int i = 0; i < m_countOfMiss; i++)
        //    {
        //        // Add only miss

        //        UInt64 targetGUID = ReadUInt64();
        //        SpellMissInfo missCondition = (SpellMissInfo)ReadByte();

        //        if (missCondition == SpellMissInfo.SPELL_MISS_REFLECT)
        //        {
        //            byte reflectResult = ReadByte();
        //        }

        //    }


        //    UInt32 m_targetMask = ReadUInt32();

        //    if ((m_targetMask & (SpellCastTargetFlags.TARGET_FLAG_UNIT | SpellCastTargetFlags.TARGET_FLAG_PVP_CORPSE | SpellCastTargetFlags.TARGET_FLAG_OBJECT | SpellCastTargetFlags.TARGET_FLAG_CORPSE | SpellCastTargetFlags.TARGET_FLAG_UNK2)) > 0)
        //    {
        //        if ((m_targetMask & SpellCastTargetFlags.TARGET_FLAG_UNIT) > 0)
        //        {
        //            ulong m_unitTarget = popGuid();
        //        }
        //        else if ((m_targetMask & (SpellCastTargetFlags.TARGET_FLAG_OBJECT | SpellCastTargetFlags.TARGET_FLAG_OBJECT_UNK)) > 0)
        //        {
        //            ulong m_GOTarget = popGuid();
        //        }
        //        else if ((m_targetMask & (SpellCastTargetFlags.TARGET_FLAG_CORPSE | SpellCastTargetFlags.TARGET_FLAG_PVP_CORPSE)) > 0)
        //        {
        //            ulong m_CorpseTargetGUID = popGuid();
        //        }
        //        else
        //        {
        //            ulong none = popGuid();
        //        }
        //    }

        //    if ((m_targetMask & (SpellCastTargetFlags.TARGET_FLAG_ITEM | SpellCastTargetFlags.TARGET_FLAG_TRADE_ITEM)) > 0)
        //    {
        //        ulong m_itemTarget = popGuid();
        //    }

        //    if ((m_targetMask & SpellCastTargetFlags.TARGET_FLAG_SOURCE_LOCATION) > 0)
        //    {
        //        float m_srcX = ReadSingle();
        //        float m_srcY = ReadSingle();
        //        float m_srcZ = ReadSingle();
        //    }

        //    if ((m_targetMask & SpellCastTargetFlags.TARGET_FLAG_DEST_LOCATION) > 0)
        //    {
        //        float m_destX = ReadSingle();
        //        float m_destY = ReadSingle();
        //        float m_destZ = ReadSingle();
        //    }

        //    if ((m_targetMask & SpellCastTargetFlags.TARGET_FLAG_STRING) > 0)
        //    {
        //        string m_strTarget = ReadString();
        //    }

        //    if ((castFlags & SpellCastFlags.CAST_FLAG_AMMO) > 0)
        //    {
        //        UInt32 ammoDisplayID = ReadUInt32();
        //        UInt32 ammoInventoryType = ReadUInt32();

        //    }


        //    return Validate();
        //}


    }
}
